﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Windows;

namespace Kugar.Core.MVVM
{
    /// <summary>
    ///     实现了 INotifyPropertyChanged, INotifyDataErrorInfo的ViewModel类
    ///     用于MVVM模式中的ViewModel基类
    /// </summary>
    /// <seealso cref="http://weblogs.asp.net/fredriknormen/archive/2009/11/22/silverlight-4-and-asynchronous-validation-with-inotifydataerrorinfo.aspx"/>
    public abstract class ViewModelBase : INotifyPropertyChanged, INotifyDataErrorInfo
    {
        public event PropertyChangedEventHandler PropertyChanged;
        public event EventHandler<DataErrorsChangedEventArgs> ErrorsChanged;

        public virtual bool IsBusy { set; get; }

        private Dictionary<string, List<ValidationErrorInfo>> _errors =
                      new Dictionary<string, List<ValidationErrorInfo>>();


        protected void RemoveErrorFromPropertyAndNotifyErrorChanges(
                                 string propertyName,
                                 int errorCode)
        {
            if (_errors.ContainsKey(propertyName))
            {
                RemoveErrorFromPropertyIfErrorCodeAlreadyExist(propertyName, errorCode);

                OnErrorsChanged(propertyName);
            }
        }

        private void RemoveErrorFromPropertyIfErrorCodeAlreadyExist(
                                 string propertyName,
                                 int errorCode)
        {
            if (_errors.ContainsKey(propertyName))
            {
                var errorToRemove = _errors[propertyName].SingleOrDefault(
                                       error => error.ErrorCode == errorCode);

                if (errorToRemove != null)
                {
                    _errors[propertyName].Remove(errorToRemove);




                    if (_errors[propertyName].Count == 0)
                        _errors.Remove(propertyName);
                }
            }
        }
        protected void AddErrorToPropertyAndNotifyErrorChanges(
                                  string propertyName,
                                  ValidationErrorInfo errorInfo)
        {
            RemoveErrorFromPropertyIfErrorCodeAlreadyExist(propertyName, errorInfo.ErrorCode);
            if (!_errors.ContainsKey(propertyName))
                _errors.Add(propertyName, new List<ValidationErrorInfo>());

            _errors[propertyName].Add(errorInfo);

            OnErrorsChanged(propertyName);
        }


        public IEnumerable GetErrors(string propertyName)
        {
            if (!_errors.ContainsKey(propertyName))
                return _errors.Values;

            return _errors[propertyName];
        }


        public bool HasErrors
        {
            get { return this._errors.Count > 0; }
        }


        private void OnErrorsChanged(string propertyName)
        {
            if (ErrorsChanged != null)
                ErrorsChanged(this, new DataErrorsChangedEventArgs(propertyName));
        }


        protected void OnPropertyChanged(string propertyName)
        {
            if (PropertyChanged != null)
                PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
        }
    }

    /// <summary>
    ///     实现了 INotifyPropertyChanged, INotifyDataErrorInfo的ViewModel类,该类继承自DependencyObject
    ///     用于MVVM模式中的ViewModel基类
    /// </summary>
    public abstract class ViewModelBaseDO : DependencyObject, INotifyPropertyChanged, INotifyDataErrorInfo
    {
        public event PropertyChangedEventHandler PropertyChanged;
        public event EventHandler<DataErrorsChangedEventArgs> ErrorsChanged;

        public virtual bool IsBusy { protected set; get; }

        private Dictionary<string, List<ValidationErrorInfo>> _errors =
                      new Dictionary<string, List<ValidationErrorInfo>>();


        protected void RemoveErrorFromPropertyAndNotifyErrorChanges(
                                 string propertyName,
                                 int errorCode)
        {
            if (_errors.ContainsKey(propertyName))
            {
                RemoveErrorFromPropertyIfErrorCodeAlreadyExist(propertyName, errorCode);

                NotifyErrorsChanged(propertyName);
            }
        }

        private void RemoveErrorFromPropertyIfErrorCodeAlreadyExist(
                                 string propertyName,
                                 int errorCode)
        {
            if (_errors.ContainsKey(propertyName))
            {
                var errorToRemove = _errors[propertyName].SingleOrDefault(
                                       error => error.ErrorCode == errorCode);

                if (errorToRemove != null)
                {
                    _errors[propertyName].Remove(errorToRemove);




                    if (_errors[propertyName].Count == 0)
                        _errors.Remove(propertyName);
                }
            }
        }
        protected void AddErrorToPropertyAndNotifyErrorChanges(
                                  string propertyName,
                                  ValidationErrorInfo errorInfo)
        {
            RemoveErrorFromPropertyIfErrorCodeAlreadyExist(propertyName, errorInfo.ErrorCode);
            if (!_errors.ContainsKey(propertyName))
                _errors.Add(propertyName, new List<ValidationErrorInfo>());

            _errors[propertyName].Add(errorInfo);

            NotifyErrorsChanged(propertyName);
        }


        public IEnumerable GetErrors(string propertyName)
        {
            if (!_errors.ContainsKey(propertyName))
                return _errors.Values;

            return _errors[propertyName];
        }


        public bool HasErrors
        {
            get { return this._errors.Count > 0; }
        }


        private void NotifyErrorsChanged(string propertyName)
        {
            if (ErrorsChanged != null)
                ErrorsChanged(this, new DataErrorsChangedEventArgs(propertyName));
        }


        protected void NotifyPropertyChanged(string propertyName)
        {
            if (PropertyChanged != null)
                PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
        }
    }

    public class ValidationErrorInfo
    {
        public int ErrorCode { get; set; }

        public string ErrorMessage { get; set; }

        public override string ToString()
        {
            return ErrorMessage;
        }
    }

}
